#pragma once

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include "type.h"
#include "diag_engine.h"

// char stream -> token

enum class TokenType
{
    number,        // [0-9]+
    indentifier,   // 变量
    kw_int,        // int
    kw_if,         // if
    kw_else,       // else
    kw_for,        // for
    kw_break,      // break
    kw_continue,   // continue
    plus,          // +
    minus,         // -
    star,          // *
    slash,         // /
    equal,         // =
    equal_equal,   // == 
    not_equal,     // !=
    less,          // <
    less_equal,    // <=
    greater,       // >
    greater_equal, // >=
    l_parent,      // (
    r_parent,      // )
    l_brace,       // {
    r_brace,       // }
    semi,          // ;
    comma,         // ,
    eof            // end of file
};

class Token
{
public:
    TokenType tokenType; // token 的种类
    int row, col;

    int value; // for number

    const char *ptr; // for debug
    int length;

    CType *type; // for built-in type

public:
    void Dump();
    static llvm::StringRef GetSpellingText(TokenType tokenType);
};

class Lexer
{
private:
    DiagEngine &diagEngine;
    llvm::SourceMgr &mgr;

public:
    Lexer(DiagEngine &diagEngine, llvm::SourceMgr &mgr) : diagEngine(diagEngine), mgr(mgr)
    {
        unsigned id = mgr.getMainFileID();
        llvm::StringRef buf = mgr.getMemoryBuffer(id)->getBuffer();
        BufPtr = buf.begin();
        LineHeadPtr = buf.begin();
        BufEnd = buf.end();
        row = 1;
    }
    void NextToken(Token &token);

    void SaveState();
    void RestoreState();

    DiagEngine &GetDiagEngine() const
    {
        return diagEngine;
    }

private:
    struct State
    {
        const char *BufPtr;
        const char *LineHeadPtr;
        const char *BufEnd;
        int row;
    };

private:
    const char *BufPtr;
    const char *LineHeadPtr;
    const char *BufEnd;
    int row;

    State state;
};